import { _decorator, Asset, AssetManager, assetManager, AudioClip, Component, Node, SceneAsset, TextAsset } from 'cc';

export class ResMgr extends Component {

    private totalAb: number = 0;
    private nowAb: number = 0;

    private now: number = 0;
    private total: number = 0;
    public static Instance: ResMgr = null!;
    /** 
      周无邪出品
      本源码用于学习研究使用。
      作者联系方式：tuya7078（微信）。
     */
    protected onLoad(): void {
        if (ResMgr.Instance !== null) {
            this.destroy();
            return;
        }

        ResMgr.Instance = this;

    }

    public async Init() {



    }
    private async IE_LoadBundle(bundleName: string) {
        return new Promise((resolve, reject) => {
            assetManager.loadBundle(bundleName, (err, bundleData) => {
                if (err) {
                    console.log(err);
                    reject(null);
                    return;
                }
                else {
                    resolve(bundleData);
                    return;
                }
            })
        });
    }
    private async IE_LoadAllAssetsInBundle(bundle: AssetManager.Bundle, assetType) {
        return new Promise((resolve, reject) => {
            bundle.loadDir("", assetType as any, (err, infos) => {
                if (err) {
                    reject(err);
                    return;
                }
                else {
                    resolve(infos);
                }
            });
        });
    }

    private async IE_LoadAssetInBundle(bundle: AssetManager.Bundle, assetName: string, assetType) {
        return new Promise((resolve, reject) => {
            bundle.load(assetName, assetType, (err, assetData) => {
                if (err) {
                    console.log("加载失败：", assetName);

                    reject(err);
                    return;
                }
                else {
                    resolve(assetData);
                }
            });
        });
    }

    private async IE_LoadSceneInBundle(bundle: AssetManager.Bundle, sceneName: string) {
        return new Promise((resolve, reject) => {
            bundle.loadScene(sceneName, (err, sceneData) => {
                if (err) {
                    reject(err);
                    return;
                }
                else {
                    resolve(sceneData);
                    return;
                }
            });
        });
    }

    public async IE_LoadBundleAndAllAssets(bundleName: string, assetType) {
        var bundle: AssetManager.Bundle = await this.IE_LoadBundle(bundleName) as AssetManager.Bundle;
        if (bundle === null) {
            return null;
        }

        await this.IE_LoadAllAssetsInBundle(bundle, assetType);
    }

    public async IE_GetScene(bundleName: string, scenePath: string) {

        var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName);

        if (bundle === null) {
            bundle = await this.IE_LoadBundle(bundleName) as any;
            if (bundle === null) {
                // console.log("bundle load err: " + bundleName);
                return;
            }
        }


        var sceneData = await this.IE_LoadSceneInBundle(bundle, scenePath) as any;
        return sceneData;
    }

    public TryGetAsset(bundleName: string, assetPath: string) {
        var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName);
        if (bundle === null) {
            return null;
        }

        var assetData = bundle.get(assetPath);
        /*if(!assetData) {
            console.log("null ", assetPath);
        }*/
        return assetData;
    }

    public async IE_GetAsset(bundleName: string, assetPath: string, assetType) {
        var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName);
        if (bundle === null) {
            bundle = await this.IE_LoadBundle(bundleName) as any;
            if (bundle === null) {
                // console.log("bundle load err: " + bundleName);
                return;
            }
        }

        var assetData = bundle.get(assetPath);
        if (assetData) {
            console.log("找到了资源", assetData);

            return assetData; // 修改了没有返回资源的bug
        }

        assetData = await this.IE_LoadAssetInBundle(bundle, assetPath, assetType) as any;
        return assetData;
    }

    public ReleaseAsset(assetData: Asset): void {
        assetManager.releaseAsset(assetData);
    }

    public ReleaseAllAssetInBundle(bundleName): void {
        var bundle: AssetManager.Bundle = assetManager.getBundle("bundleName");
        if (bundle === null) {
            return;
        }

        bundle.releaseAll();

        assetManager.removeBundle(bundle);
    }

    // 获取资源
    public getAsset(abName: string, url: string): any {
        var abBundle: AssetManager.Bundle = assetManager.getBundle(abName) as AssetManager.Bundle;
        if (!abBundle) {
            return null;
        }

        return abBundle.get(url);
    }
    //加载单个资源
    public preloadAsset(abName: string, url: string, typeClass: any, endFunc: Function): void {
        assetManager.loadBundle(abName, (err, abBundle: AssetManager.Bundle) => {
            if (err) {
                //  console.log(err);
                return;
            }

            abBundle.load(url, typeClass, (err, asset: Asset) => {
                if (err) {
                    //  console.log(err);
                    return;
                }
                //  console.log("asset",Asset);

                if (endFunc) {
                    endFunc(asset);
                }
            });
        });
    }
    //加载资源包
    public preloadResPkg(resPkg: any, progress: Function, endFunc: Function) {
        this.totalAb = 0;
        this.nowAb = 0;

        this.total = 0;
        this.now = 0;

        for (var key in resPkg) {
            this.totalAb++;

            if (resPkg[key] instanceof Array) {
                for (let i = 0; i < resPkg[key].length; i++) {
                    this.total += resPkg[key][i].urls.length;
                }
            }
        }

        console.log("ab包个数：" + this.totalAb);
        console.log("资源个数" + this.total);
        //如果一个资源都没有就直接进入场景吧


        if (this.total <= 0) {
            if (endFunc) {
                endFunc()

            }
            return
        }



        // 加载ab包
        for (var key in resPkg) {
            assetManager.loadBundle(key, (err, bundle: AssetManager.Bundle) => {
                if (err) {
                    //   console.log("load bundle erro: ", err);
                    return;
                }

                this.nowAb++;


                if (!(resPkg[key] instanceof Array)) {
                    let infos = bundle.getDirWithPath("/");
                    this.total += (infos.length);
                }

                if (this.nowAb >= this.totalAb) { // ab包加载完毕
                    this.preloadAssetsInAssetsBundles(resPkg, progress, endFunc);
                }



            });
        }


    }
    private preloadAssetsInAssetsBundles(resPkg: any, progress: Function, endFunc: Function): void {
        for (var key in resPkg) {
            var abBundle: AssetManager.Bundle = assetManager.getBundle(key) as AssetManager.Bundle;
            if (!abBundle) {
                continue;
            }

            if (resPkg[key] instanceof Array) {
                for (let i = 0; i < resPkg[key].length; i++) {
                    // let info: any = abBundle.getDirWithPath("/");
                    // console.log(info);
                    this.loadAssetsInUrls(abBundle, resPkg[key][i].typeAsset, resPkg[key][i].urls, progress, endFunc);
                }
            }
            else {
                //   console.log("------------整包加载------------");
                let typeAsset = resPkg[key];
                let infos = abBundle.getDirWithPath("/");
                let urls: any = [];
                for (let i = 0; i < infos.length; i++) {
                    urls.push(infos[i].path);
                }

                this.loadAssetsInUrls(abBundle, typeAsset, urls, progress, endFunc);
            }
        }
    }

    private loadAndRef(abBundle: AssetManager.Bundle, url: string,
        typeAsset: any,
        progress: Function, endFunc: Function): void {

        abBundle.load(url, typeAsset, (err: any, asset: Asset) => {
            if (err) {
                console.log("load assets err: ", err);
                return;
            }
            asset.addRef(); // 增加一个引用计数;
            //   console.log("引用计数：",asset.refCount);
            this.now++;
            if (progress) {
                progress(this.now, this.total);
            }
            if (this.now >= this.total) {
                if (endFunc) {
                    endFunc();
                }
            }
        });
    }

    private loadAssetsInUrls(abBundle: AssetManager.Bundle, typeAsset: any, urls: Array<string>, progress: Function, endFunc: Function): void {
        for (let i = 0; i < urls.length; i++) {
            this.loadAndRef(abBundle, urls[i], typeAsset, progress, endFunc);
        }
    }


    //释放资源包
    public releaseResPkg(resPkg: any): void {
        for (var key in resPkg) {
            let abBundle: AssetManager.Bundle = assetManager.getBundle(key) as AssetManager.Bundle;
            if (!abBundle) {
                continue;
            }

            if (resPkg[key] instanceof Array) {
                for (let i = 0; i < resPkg[key].length; i++) {
                    this.releaseAssetsInUrls(abBundle, resPkg[key][i].typeAsset, resPkg[key][i].urls);
                }
            }
            else {
                let typeAsset = resPkg[key];
                let infos = abBundle.getDirWithPath("/");
                let urls: any = [];
                for (let i = 0; i < infos.length; i++) {
                    urls.push(infos[i].path);
                }
                this.releaseAssetsInUrls(abBundle, typeAsset, urls);
            }
        }
    }

    private releaseAssetsInUrls(abBundle: AssetManager.Bundle, typeAsset: any, urls: Array<string>): void {
        for (let i = 0; i < urls.length; i++) {
            // console.log(urls[i]);
            let asset: Asset = abBundle.get(urls[i]) as Asset;
            if (!asset) {
                continue;
            }
            //直接释放 
            //  this.ReleaseAsset(asset)
            //console.log(asset.refCount);
            //减少引用计数
            asset.decRef(true);
        }
    }

}


